using Furion;
using Furion.Schedule;
using Furion.SpecificationDocument;
using IGeekFan.AspNetCore.Knife4jUI;
using Magic.Core;
using Magic.Core.Job;
using Magic.Web.Core.Handlers.Tcp;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.JsonWebTokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
using Yitter.IdGenerator;

namespace Magic.Web.Core;

[AppStartup(9)]
public class Startup : AppStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddBStyle(m => m.UseDefault());
        services.AddConfigurableOptions<ConnectionStringsOptions>();
        services.AddConfigurableOptions<JWTSettingsOptions>();
        services.AddConfigurableOptions<CacheOptions>();
        services.AddConfigurableOptions<SnowIdOptions>();
        services.AddConfigurableOptions<SystemSettingsOptions>();
        services.AddConfigurableOptions<UploadFileOptions>();

        #region 上传文件大小限制
        long maxRequestBodySize = Convert.ToInt64(App.Configuration["MaxRequestBodySize"]);
        services.Configure<KestrelServerOptions>(options =>
        {
            options.Limits.MaxRequestBodySize = maxRequestBodySize;
        });
        services.Configure<IISServerOptions>(options =>
        {
            options.MaxRequestBodySize = maxRequestBodySize;
        });

        services.Configure<FormOptions>(o =>
        {
            o.MultipartBodyLengthLimit = maxRequestBodySize;
        });
        #endregion

        services.AddResponseCompression();

        services.SqlSugarScopeConfigure();

        services.AddUnitOfWork<SqlSugarUnitOfWork>();

        services.AddJwt<JwtHandler>(enableGlobalAuthorize: true, jwtBearerConfigure: option =>
        {
            option.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
            {
                //token认证过后的操作
                OnTokenValidated = context =>
                {
                    //获取token字符串
                    //var tokenObj = new JwtSecurityToken(((JsonWebToken)context.SecurityToken).EncodedToken);

                    ////获取claims
                    //var claimsIdentity = new ClaimsIdentity(tokenObj.Claims);
                    //var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

                    ////逻辑判断，比如当前用户不是管理员，直接返回401
                    //if (claimsIdentity.FindFirst(ClaimConst.CLAINM_NAME).Value != "超级管理员")
                    //{
                    //    Console.WriteLine($"不是超级管理员");
                    //    context.Fail("Unauthorized");
                    //    context.HttpContext.Items["OnTokenValidatedMessage"] = "不是超级管理员";
                    //}


                    return Task.CompletedTask;
                }
            };
        });

        services.AddCorsAccessor();

        // 配置远程请求
        services.AddRemoteRequest();
        services.AddControllersWithViews()
                .AddMvcFilter<RequestActionFilter>()
                .AddNewtonsoftJson(options =>
                {
                    // 首字母小写(驼峰样式)
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    // 时间格式化
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                    // 忽略循环引用
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                    // 忽略空值
                    //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                })
                .AddInjectWithUnifyResult<RestfulResultProvider>();

        services.AddViewEngine();
        services.AddSignalR();

        // 设置雪花id的workerId，确保每个实例workerId都应不同
        var workerId = ushort.Parse(App.GetConfig<SnowIdOptions>("SnowId").WorkerId);
        YitIdHelper.SetIdGenerator(new IdGeneratorOptions { WorkerId = workerId });

        // 定时任务
        services.AddSchedule(options =>
        {
            options.AddJob(App.EffectiveTypes.ScanToBuilders());
        });

        // 注册EventBus服务
        services.AddEventBus(builder =>
        {
            // 注册 Log 日志订阅者
            builder.AddSubscriber<LogEventSubscriber>();
        });

        #region Tcp
        services.AddTcpService(config =>
        {
            //更多tcpService的config配置请看 http://rrqm_home.gitee.io/touchsocket/docs/current/tcpservice/
            config.SetListenIPHosts(7789)
            .ConfigurePlugins(a =>
            {
                a.Add<TcpServicePlugin>();
            });
        });
        #endregion
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        // 添加状态码拦截中间件
        app.UseUnifyResultStatusCodes();

        app.UseHttpsRedirection(); // 强制https
        app.UseStaticFiles();

        app.UseScheduleUI();

        app.UseRouting();

        app.UseCorsAccessor();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseResponseCompression();

        app.UseKnife4UI(options =>
        {
            options.RoutePrefix = "api";  // 配置 Knife4UI 路由地址，现在是 /api
            foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
            {
                options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
            }
        });

        app.UseInject(string.Empty);

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<ChatHub>("/hubs/chathub");
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });

        //直接将vue项目丢在wwwroot文件夹内，以下配置是防止F5刷新出现404
        app.Run(async (context) =>
        {
            context.Response.ContentType = "text/html";
            await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "index.html"));
        });

    }


}
